package cn.ranko.shiro.realm;

import cn.ranko.shiro.model.SysUser;
import cn.ranko.shiro.service.SysUserService;
import cn.ranko.shiro.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * Created by user on 2017/9/5.
 */
public class ShiroDbRealm  extends AuthorizingRealm {

    UserService userService;

    public static final String SESSION_USER_KEY = "APP_USER";

    /**
     * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用,负责在应用程序中决定用户的访问控制的方法
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SysUser sysUser = (SysUser) SecurityUtils.getSubject().getSession().getAttribute(ShiroDbRealm.SESSION_USER_KEY);
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        if(sysUser.getRolenames().size()>0){
            for(String rolename:sysUser.getRolenames()){
                simpleAuthorizationInfo.addRole(rolename);
            }
        }

        if(sysUser.getPermissions().size()>0){
            for(String permission:sysUser.getPermissions()){
                simpleAuthorizationInfo.addStringPermission(permission);
            }
        }
        return simpleAuthorizationInfo;
    }


    /**
     * 认证回调函数，登录信息和用户验证信息验证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 把token转换成User对象
        SysUser userLogin = tokenToUser((UsernamePasswordToken) authenticationToken);
        // 验证用户是否可以登录
        SysUser validateUser = userService.selectForLogin(userLogin);
        if(validateUser == null)
            return null; // 异常处理，找不到数据
        // 设置session
        Session session = SecurityUtils.getSubject().getSession();
        session.setAttribute(ShiroDbRealm.SESSION_USER_KEY, validateUser);
        //当前 Realm 的 name
        String realmName = this.getName();
        //登陆的主要信息: 可以是一个实体类的对象, 但该实体类的对象一定是根据 token 的 username 查询得到的.
        Object principal = authenticationToken.getPrincipal();
        return new SimpleAuthenticationInfo(principal, userLogin.getLoginpass(), realmName);
    }

    private SysUser tokenToUser(UsernamePasswordToken authcToken) {
        SysUser user = new SysUser();
        user.setUsername(authcToken.getUsername());
        user.setLoginpass(String.valueOf(authcToken.getPassword()));
        return user;
    }

    public UserService getUserService() {
        return userService;
    }

    public void setUserService(UserService userService) {
        this.userService = userService;
    }
}
